<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>




 * 			

<script>
/**
 * 高阶函数
 * 		高阶函数特点
 * 			1.接受函数类型的参数。
 * 			2.返回值是函数。
 * 			3.高阶函数具有可扩展性。
 * 			接受一个参数为函数的参数，并返回一个函数
 * 		常见的高阶函数：
 * 			1.定时器 setTimeout(); setInterval()
 * 			2.Promise();
 * 			3.数组相关：forEach();filter();map();reduce();find();findIndex()
 * 			4.函数对象bind();
 */

var Fun1 = (fn) => {
	return (name) => {
		fn(name)
	}
}
function say(name) {
	console.log('哈哈，那个睡叫:' + name)
}
var func = Fun1(say)
func('波仔')
/**
 * 闭包
 * 		闭包是指有权访问另一个函数作用域中的变量的函数
 * 		闭包的特点
			1.函数嵌套函数
			2.函数内部可以引用外部的参数和变量
			3.参数和变量不会被垃圾回收机制回收，直到第二个函数执行完并被设置为null
		闭包的优点
			1.希望一个变量长期驻扎在内存中
			2.避免全局变量的污染
			3.私有成员的存在
 */

function fn() {
    var num = 1;
    function fun() {
        console.log(num)
    }
    fun()
}
fn()


/**
 * 函数柯里化
 * 柯里化函数利用了闭包的特点，传入的参数会做存储留用，等到参数传完了，再对参数做处理。
 */
// 1、柯里化函数
function addCurrying(a) {
    return function (b) {
        return function (c) {
            return a + b + c;
        }
    }
}
// addCurrying(1)保存a变量的作用域
// addCurrying(1)(2)保存a变量和b变量的作用域
// addCurrying(1)(2)(3)所有变量会被垃圾回收机制回收
addCurrying(1)(2)(3) 
var fun_2_step = addCurrying(1)(2); 
fun_2_step(3)
fun_2_step = null; // 当设置fun_2_step为null时，a,b,c才会被垃圾回收机制回收


// 2、柯里化通用式
// 把一个普通函数转成一个柯里化函数
function currying(fn, args) {
	// console.log(func, args)
	// func的形参个数
	var arity = fn.length;
	// 上一次传入的参数
	var args = args || [];

	return function() {
		// 将参数转为数组
		var _args = [].slice.call(arguments);
		// 将参数合并
		Array.prototype.unshift.apply(_args, args);
		if (_args.length < arity) {
			return currying.call(null, fn, _args); 
		}
        return fn.apply(null, _args);
	}
}
function add(a,b,c) {
	console.log(a,b,c)
}
//test
currying(add, [1])(2)(3) // => add(a){ return (b) => { return (c) => { console.log(a,b,c) } } }

// es6的写法
/*
function currying(func, args = []) {
    let arity = func.length;

    return function (..._args) {
        _args.unshift(...args);

        if(_args.length < arity) {
            return currying(func, _args);
        }

        return func(..._args);
    }
}
*/

/**
 * 反柯里化通用方法
 */

function uncurrying(fn) {
	return function() {
		var obj = [].shift.call(arguments);
		console.log('obj', obj)
		return fn.apply(obj, arguments)
	}
}
// function uncurrying(fn) {
//     return function (...args) {
//         return fn.call(...args);
//     }
// }
const checkType = uncurrying(Object.prototype.toString);
checkType(1)

</script>
</body>
</html>